﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Common.Utilities;
using Common.Utilities.Dispatcher;

namespace Workflows.Components.TextMining.Collapse
{
    /// <summary>
    /// 
    /// </summary>
    public class TableStatsWorker:IWorker
    {
        #region IWorker
        private Thread _workerThread;
        private TableStatsInstruction _instruction;
        private TableStatsOutput _output;
        private Guid _JobTicketID;
        private RunContext _context;
        private string _WorkflowName;
        private string _ComponentName;

        /// <summary>
        /// 
        /// </summary>
        public string ComponentName
        {
            get { return _ComponentName; }
        }

        /// <summary>
        /// 
        /// </summary>
        public string WorkflowName
        {
            get { return _WorkflowName; }
        }

        public Thread WorkerThread
        {
            get { return _workerThread; }
        }

        public InstructionBase Instruction
        {
            get { return _instruction; }
        }

        public ResultBase Output
        {
            get { return _output; }
        }

        public Type ComponentType
        {
            get { return typeof(TableStatsComponent); }
        }

        public RunContext Context
        {
            get { return _context; }
            set { _context = value; }
        }

        public void SetInstruction(Guid ticketGuid, InstructionBase request, string workflowName, string componentName)
        {
            this._JobTicketID = ticketGuid;
            this._instruction = (TableStatsInstruction) request;
            this._WorkflowName = workflowName;
            this._ComponentName = componentName;
        }

        public void SetInstruction(RunContext context, Guid ticketGuid, InstructionBase request, string workflowName, string componentName)
        {
            this._JobTicketID = ticketGuid;
            this._instruction = (TableStatsInstruction)request;
            this._context = context;
            this._WorkflowName = workflowName;
            this._ComponentName = componentName;
        }

        public void DoWork()
        {
            if(this.WorkerStartedEvent !=null)
            {
                this.WorkerStartedEvent(this._JobTicketID, this, this.GetType(), this._instruction);
            }
            this._workerThread = Thread.CurrentThread;
            this.GetTableStats();
        }

        public void DoWorkAsync()
        {
            if (this.WorkerStartedEvent != null)
            {
                this.WorkerStartedEvent(this._JobTicketID, this, this.GetType(), this._instruction);
            }
            this._workerThread = new Thread(new ThreadStart(this.GetTableStats));
            this._workerThread.Start();
        }

        public void CancelWork()
        {
            if(this._workerThread !=null && this._workerThread.IsAlive)
            {
                this._workerThread.Abort();
                if(this.WorkerCancelledEvent !=null)
                {
                    this.WorkerCancelledEvent(this._JobTicketID, this.GetType(), this._instruction);
                }
            }
        }

        public event WorkerStarted WorkerStartedEvent;
        public event WorkerFinished WorkerFinishedEvent;
        public event WorkerHasError WorkerErredEvent;
        public event WorkerCancelled WorkerCancelledEvent;
        public event WorkerStatusChanged WorkerStatusChangedEvent;
        #endregion

        #region work
        private void GetTableStats()
        {
            try
            {
                int totalRecs = 0;
                Dictionary<string,TableFieldStats<IComparable>> fieldStats=new Dictionary<string, TableFieldStats<IComparable>>();

                TableColumn[] cols = DbUtil.GetTableColumns(DataProviderType.MSSQL, this._instruction.ConnStr,
                                                            string.Empty, this._instruction.TableName);
                int columnCalculated = 0;
                foreach(TableColumn col in cols)
                {
                    bool continueCalculate = false;
                    if(FieldDataType.IsNumber(col.DbType))
                    {
                        continueCalculate = true;
                    }
                    else if (FieldDataType.IsDateTime(col.DbType))
                    {
                        continueCalculate = true;
                    }
                    else if (FieldDataType.IsStringType(col.DbType))
                    {
                        continueCalculate = true;
                    }

                    if(continueCalculate)
                    {
                        if(this.WorkerStatusChangedEvent !=null)
                        {
                            int percent = (columnCalculated*100)/cols.Length;
                            string msg = string.Format("Calculating stats for column {0} of table {1}", col.ColumnName,
                                                       this._instruction.TableName);
                            this.WorkerStatusChangedEvent(this._JobTicketID, this.GetType(), this._instruction, this.WorkflowName, this.ComponentName, msg,
                                                          percent);
                        }
                        TableFieldStats<IComparable> fieldStat =
                            new TableFieldStats<IComparable>(this._instruction.ConnStr, this._instruction.TableName,
                                                             col.ColumnName);
                        totalRecs = Math.Max(totalRecs, fieldStat.NonNullValueCount);
                        fieldStats.Add(col.ColumnName,fieldStat);
                    }

                }

                this._output = new TableStatsOutput(this._instruction.OwnerComponentID, this._JobTicketID, totalRecs,
                                                    fieldStats);
                if(this.WorkerFinishedEvent !=null)
                {
                    this.WorkerFinishedEvent(this._JobTicketID, this.GetType(), this._instruction, this._output);
                }
            }
            catch(Exception ex)
            {
                if(this.WorkerErredEvent != null)
                {
                    this.WorkerErredEvent(this._JobTicketID, this.GetType(), this._instruction, ex.ToString(),true);
                }
            }
        }
        #endregion
    }
}
